package com.newy.core.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;

import com.newy.domain.sys.User;
import com.newy.service.sys.LogService;
import com.newy.service.sys.ParamService;
import com.newy.service.sys.UserService;

/**
 * 系统上下文类，主要有以下用处：
 * ·系统启动后做一些初始化工作；
 * ·方便地获取spring容器中的对象
 * ·提供了保存和获取当前用户登陆信息的方法
 * ·提供了获取request, response和资源绝对路径的方法
 * @author linzongxue
 * @create_date 2011-12-20
 */
public class AppContext{
	private static final Logger logger = LoggerFactory.getLogger(AppContext.class);
	
	/**
	 * 包根路径
	 */
	public static final String BASE_PACKAGE = AppContext.class.getName().replaceFirst(".core.web.*$", "");
	
	/**
	 * 在session中保存用户登陆信息的属性名
	 */
	private static final String SESS_ATTR_LOGIN_USER = "LOGIN_USER";
	
	private static WebApplicationContext webAppContext;
	
	private static ThreadLocal<HttpServletRequest> request = new ThreadLocal<HttpServletRequest>();
	private static ThreadLocal<HttpServletResponse> response = new ThreadLocal<HttpServletResponse>();
	
	/**
	 * 系统的初始化工作
	 */
	public static void init(WebApplicationContext webAppContext){
		logger.info("系统正在进行初始化……");
		AppContext.webAppContext = webAppContext;
		getBean(ParamService.class).initParamDefs();
		getBean(UserService.class).initUserData();
		getBean(LogService.class).checkUnexceptedLogout();
		logger.info("系统初始化完成");
	}

	/**
	 * 获取spring容器中的对象, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		return (T) webAppContext.getBean(name);
	}

	/**
	 * 获取spring容器中的对象, 自动转型为所赋值对象的类型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
		return webAppContext.getBean(requiredType);
	}
	
	/**
	 * 设置当前登陆的用户信息。</br>
	 * 【注意：此方法只允许UserManager的login方法调用】
	 */
	public static void setLoginUser(User user){
		StackTraceElement ste = Thread.currentThread().getStackTrace()[2];
		String method = ste.getClassName() + "." + ste.getMethodName();
		if (!method.equals(UserService.class.getName() + ".login"))
			throw new RuntimeException("AppConext.setLoginUser()方法禁止在此处调用：" + method);
		
		getRequest().getSession().setAttribute(SESS_ATTR_LOGIN_USER, user);
	}
	
	/**
	 * 获取当前登陆的用户对象。
	 */
	public static User getLoginUser(){
		return (User)getRequest().getSession().getAttribute(SESS_ATTR_LOGIN_USER);
	}
	
	/**
	 * 获取request请求对象
	 */
	public static HttpServletRequest getRequest(){
		HttpServletRequest req = request.get();
		if (req == null)
			throw new RuntimeException("AppContext未绑定请求对象");
		return req;
	}
	
	/**
	 * 获取request请求对象
	 */
	public static HttpServletResponse getResponse(){
		HttpServletResponse resp = response.get();
		if (resp == null)
			throw new RuntimeException("AppContext未绑定应答对象");
		return resp;
	}

	/**
	 * 将系统中的相对路径转换为绝对路径
	 */
	public static String getWebRealPath(String path){
		return webAppContext.getServletContext().getRealPath(path);
	}
	
	/**
	 * 获取系统参数值，返回字符串
	 * @param name 参数名称
	 */
	public static String getSysParam(String name){
		return getBean(ParamService.class).getSysString(name);
	}
	
	/**
	 * 此方法提供给servlet或filter调用，目的是记住当前线程的请求对象和应答对象，方便写程序。
	 * 务必保证所有请求在进入web层之前先调用此方法。
	 */
	static void bindRequestAndResponse(HttpServletRequest req, HttpServletResponse rep){
		request.set(req);
		response.set(rep);
	}
}
